home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Contributed / SpriteWorld / SpriteWorld Files / Utils / Multi-Screen Scrolling.c < prev    next >
Encoding:
Text File  |  2000-10-06  |  31.8 KB  |  952 lines  |  [TEXT/CWIE]

  1. ///--------------------------------------------------------------------------------------
  2. //    Multi-Screen Scrolling.c
  3. //
  4. //    By Vern Jensen. Created 1/1/97
  5. ///--------------------------------------------------------------------------------------
  6.  
  7.  
  8. #ifndef __SPRITEWORLD__
  9. #include <SpriteWorld.h>
  10. #endif
  11.  
  12. #ifndef __SPRITEWORLDUTILS__
  13. #include <SpriteWorldUtils.h>
  14. #endif
  15.  
  16. #ifndef __SCROLLING__
  17. #include <Scrolling.h>
  18. #endif
  19.  
  20. #ifndef __TILING__
  21. #include <Tiling.h>
  22. #endif
  23.  
  24. #ifndef __MULTISCREENSCROLLING__
  25. #include <Multi-Screen Scrolling.h>
  26. #endif
  27.  
  28.  
  29. ///--------------------------------------------------------------------------------------
  30. //    SWSetUpDuplicateSpriteWorld
  31. ///--------------------------------------------------------------------------------------
  32.  
  33. SW_FUNC void SWSetUpDuplicateSpriteWorld(
  34.     SpriteWorldPtr masterSpriteWorldP,
  35.     SpriteWorldPtr duplicateSpriteWorldP)
  36. {
  37.     FramePtr    dupFrameP;
  38.     
  39.         // Dispose the deadSpriteLayer of the duplicateSpriteWorldP
  40.     SWDisposeSpriteLayer(&duplicateSpriteWorldP->deadSpriteLayerP);
  41.     
  42.         // Share SpriteLayers
  43.     duplicateSpriteWorldP->headSpriteLayerP = masterSpriteWorldP->headSpriteLayerP;
  44.     duplicateSpriteWorldP->tailSpriteLayerP = masterSpriteWorldP->tailSpriteLayerP;
  45.     duplicateSpriteWorldP->deadSpriteLayerP = masterSpriteWorldP->deadSpriteLayerP;
  46.     
  47.         // Copy DrawProc info and scrollRectMoveBounds
  48.     duplicateSpriteWorldP->offscreenDrawProc = masterSpriteWorldP->offscreenDrawProc;
  49.     duplicateSpriteWorldP->screenDrawProc = masterSpriteWorldP->screenDrawProc;
  50.     duplicateSpriteWorldP->doubleRectDrawProc = masterSpriteWorldP->doubleRectDrawProc;
  51.     duplicateSpriteWorldP->scrollRectMoveBounds = masterSpriteWorldP->scrollRectMoveBounds;
  52.     
  53.         // Copy interlacing information for back, work, window, and extra frames.
  54.     dupFrameP = duplicateSpriteWorldP->backFrameP;
  55.     if (dupFrameP != NULL && masterSpriteWorldP->backFrameP != NULL)
  56.     {
  57.         dupFrameP->interlacingIsOn = masterSpriteWorldP->backFrameP->interlacingIsOn;
  58.         dupFrameP->skipOddLines = masterSpriteWorldP->backFrameP->skipOddLines;
  59.     }
  60.     
  61.     dupFrameP = duplicateSpriteWorldP->workFrameP;
  62.     if (dupFrameP != NULL && masterSpriteWorldP->workFrameP != NULL)
  63.     {
  64.         dupFrameP->interlacingIsOn = masterSpriteWorldP->workFrameP->interlacingIsOn;
  65.         dupFrameP->skipOddLines = masterSpriteWorldP->workFrameP->skipOddLines;
  66.     }
  67.  
  68.     dupFrameP = duplicateSpriteWorldP->windowFrameP;
  69.     if (dupFrameP != NULL && masterSpriteWorldP->windowFrameP != NULL)
  70.     {
  71.         dupFrameP->interlacingIsOn = masterSpriteWorldP->windowFrameP->interlacingIsOn;
  72.         dupFrameP->skipOddLines = masterSpriteWorldP->windowFrameP->skipOddLines;
  73.     }
  74.     
  75.     dupFrameP = duplicateSpriteWorldP->extraBackFrameP;
  76.     if (dupFrameP != NULL && masterSpriteWorldP->extraBackFrameP != NULL)
  77.     {
  78.         dupFrameP->interlacingIsOn = masterSpriteWorldP->extraBackFrameP->interlacingIsOn;
  79.         dupFrameP->skipOddLines = masterSpriteWorldP->extraBackFrameP->skipOddLines;
  80.     }
  81.     
  82.         // Copy tiling stuff
  83.     duplicateSpriteWorldP->extraBackFrameP = masterSpriteWorldP->extraBackFrameP;
  84.     duplicateSpriteWorldP->tileLayerArray = masterSpriteWorldP->tileLayerArray;
  85.     duplicateSpriteWorldP->lastActiveTileLayer = masterSpriteWorldP->lastActiveTileLayer;
  86.     duplicateSpriteWorldP->tileRectDrawProc = masterSpriteWorldP->tileRectDrawProc;
  87.     duplicateSpriteWorldP->tileFrameArray = masterSpriteWorldP->tileFrameArray;
  88.     duplicateSpriteWorldP->curTileImage = masterSpriteWorldP->curTileImage;
  89.     duplicateSpriteWorldP->maxNumTiles = masterSpriteWorldP->maxNumTiles;
  90.     duplicateSpriteWorldP->tileWidth = masterSpriteWorldP->tileWidth;
  91.     duplicateSpriteWorldP->tileHeight = masterSpriteWorldP->tileHeight;
  92.     duplicateSpriteWorldP->tileMaskDrawProc = masterSpriteWorldP->tileMaskDrawProc;
  93.     duplicateSpriteWorldP->partialMaskDrawProc = masterSpriteWorldP->partialMaskDrawProc;
  94. }
  95.  
  96.  
  97. ///--------------------------------------------------------------------------------------
  98. //    SWDisposeDuplicateSpriteWorld
  99. ///--------------------------------------------------------------------------------------
  100.  
  101. SW_FUNC void SWDisposeDuplicateSpriteWorld(
  102.     SpriteWorldPtr    spriteWorldP)
  103. {
  104.     if (spriteWorldP != NULL)
  105.     {
  106.         SWUnlockSpriteWorld(spriteWorldP);
  107.  
  108.         SWDisposeFrame(&spriteWorldP->backFrameP);
  109.         SWDisposeFrame(&spriteWorldP->workFrameP);
  110.         SWDisposeWindowFrame(&spriteWorldP->windowFrameP);
  111.         
  112.         SWExitTilingForDuplicateSpriteWorld(spriteWorldP);
  113.         SWSyncSpriteWorldToVBL(spriteWorldP, false);
  114.         
  115.         DisposePtr((Ptr)spriteWorldP);
  116.     }
  117. }
  118.  
  119.  
  120. ///--------------------------------------------------------------------------------------
  121. //    SWInitTilingForDuplicateSpriteWorld
  122. ///--------------------------------------------------------------------------------------
  123.  
  124. SW_FUNC OSErr SWInitTilingForDuplicateSpriteWorld(
  125.     SpriteWorldPtr    spriteWorldP,
  126.     short             tileHeight,
  127.     short            tileWidth)
  128. {
  129.     OSErr     err = noErr;
  130.     
  131.     
  132.     if (spriteWorldP->tilingIsInitialized)
  133.     {
  134.         err = kTilingAlreadyInitialized;
  135.     }
  136.     
  137.     if (err == noErr)
  138.     {
  139.         spriteWorldP->tilingIsOn = true;
  140.         spriteWorldP->tilingIsInitialized = true;
  141. //        spriteWorldP->lastActiveTileLayer = 0;        // <-- Copied from master SpriteWorld
  142. //        spriteWorldP->maxNumTiles = maxNumTiles;    // <-- Copied from master SpriteWorld
  143.         spriteWorldP->tileHeight = tileHeight;
  144.         spriteWorldP->tileWidth = tileWidth;
  145.     }
  146.     
  147.     if (err == noErr)
  148.     {
  149.             // Create both tiling cache and changedTiles array of rects
  150.             // (We need the changedTilesArray even for a duplicate SpriteWorld.)
  151.         err = SWInitTilingCache(spriteWorldP);
  152.     }
  153.     
  154.     
  155.     SWSetStickyIfError(err);
  156.     return err;
  157. }
  158.  
  159.  
  160. ///--------------------------------------------------------------------------------------
  161. //    SWExitTilingForDuplicateSpriteWorld
  162. ///--------------------------------------------------------------------------------------
  163.  
  164. SW_FUNC void SWExitTilingForDuplicateSpriteWorld(
  165.     SpriteWorldPtr    spriteWorldP)
  166. {
  167.         // Was tiling ever initialized?
  168.     if (spriteWorldP->tilingIsInitialized)
  169.     {
  170.         DisposePtr((Ptr)spriteWorldP->changedTiles);
  171.         DisposePtr((Ptr)spriteWorldP->tilingCache[0]);    // Dispose the data
  172.         DisposePtr((Ptr)spriteWorldP->tilingCache);        // Dispose the array of pointers
  173.         
  174.         spriteWorldP->tilingIsInitialized = false;
  175.         spriteWorldP->tilingIsOn = false;
  176.     }
  177. }
  178.  
  179.  
  180. #pragma mark -
  181. ///--------------------------------------------------------------------------------------
  182. //    SWProcessMultiScreenSpriteWorld
  183. ///--------------------------------------------------------------------------------------
  184.  
  185. SW_FUNC void SWProcessMultiScreenSpriteWorld(
  186.     SpriteWorldPtr spriteWorldP)
  187. {
  188.     gSWCurrentSpriteWorld = spriteWorldP;
  189.     
  190.         // Call the scrolling world move proc
  191.     if (spriteWorldP->worldMoveProc != NULL)
  192.     {
  193.         (*spriteWorldP->worldMoveProc)(spriteWorldP, spriteWorldP->followSpriteP);
  194.     }
  195.     
  196.     
  197.         // Move visScrollRect
  198.     if (spriteWorldP->horizScrollDelta || spriteWorldP->vertScrollDelta)
  199.     {
  200.         SWOffsetVisScrollRect(spriteWorldP, 
  201.             spriteWorldP->horizScrollDelta, 
  202.             spriteWorldP->vertScrollDelta);
  203.     }
  204.     
  205.     gSWCurrentSpriteWorld = NULL;
  206. }
  207.  
  208.  
  209. ///--------------------------------------------------------------------------------------
  210. //    SWFinishProcessingMultiScreenSW
  211. ///--------------------------------------------------------------------------------------
  212.  
  213. SW_FUNC void SWFinishProcessingMultiScreenSW(
  214.     SpriteWorldPtr spriteWorldP)
  215. {
  216.     gSWCurrentSpriteWorld = spriteWorldP;
  217.     
  218.         // Process any Sprites in a non-scrolling SpriteLayer
  219.     SWProcessNonScrollingLayers(spriteWorldP);
  220.     
  221.     gSWCurrentSpriteWorld = NULL;
  222. }
  223.  
  224.  
  225. ///--------------------------------------------------------------------------------------
  226. //    SWAnimateMultiScreenSpriteWorld. The only differences between this function
  227. //    and the normal SWAnimateScrollingSpriteWorld are:
  228. //    A) The code that assigns the destFrameRect to the oldFrameRect, etc. was moved to
  229. //     SWFinishMultiScreenAnimation where applicable.
  230. //    B) The code at the very beginning of this function that checks the frameHasOccurred
  231. //       variable was removed, since the user has to do this for multi-screen animations.
  232. //    C) The name was changed. :-)
  233. ///--------------------------------------------------------------------------------------
  234.  
  235. SW_FUNC void SWAnimateMultiScreenSpriteWorld(
  236.     SpriteWorldPtr spriteWorldP)
  237. {
  238.     UpdateRectStructPtr            curRectStructP,
  239.                                 nextRectStructP;
  240.     register SpriteLayerPtr     curSpriteLayerP;
  241.     register SpritePtr             curSpriteP;
  242.     SpritePtr                     headActiveSpriteP = NULL;    // Tail of active sprite list
  243.     SpritePtr                    headIdleSpriteP = NULL;        // Tail of idle sprite list
  244.     SpritePtr                     curActiveSpriteP = NULL;
  245.     SpritePtr                     curIdleSpriteP = NULL;
  246.     Rect                        *visScrollRectP = &spriteWorldP->visScrollRect;
  247.     Rect                        tempDstRect, tempSrcRect;
  248.     short                        hScrollDelta, vScrollDelta, curTileLayer;
  249.     short                        oldVertScrollRectOffset, oldHorizScrollRectOffset;
  250.  
  251.     SW_ASSERT(spriteWorldP != NULL);
  252.     SW_ASSERT(spriteWorldP->backFrameP->isFrameLocked);
  253.     SW_ASSERT(spriteWorldP->workFrameP->isFrameLocked);
  254.     SW_ASSERT(spriteWorldP->windowFrameP->isFrameLocked);
  255.     
  256.     gSWCurrentSpriteWorld = spriteWorldP;
  257.     
  258.     oldVertScrollRectOffset = spriteWorldP->backRect.bottom * 
  259.         (spriteWorldP->oldVisScrollRect.top / spriteWorldP->backRect.bottom);
  260.     
  261.     oldHorizScrollRectOffset = spriteWorldP->backRect.right *
  262.         (spriteWorldP->oldVisScrollRect.left / spriteWorldP->backRect.right);
  263.     
  264.     
  265.         // Add the deadSpriteLayer if there are any Sprites in it.
  266.     if ( spriteWorldP->deadSpriteLayerP->headSpriteP != NULL )
  267.     {
  268.         SWAddSpriteLayer(spriteWorldP, spriteWorldP->deadSpriteLayerP);
  269.     }
  270.     
  271.     
  272.     hScrollDelta = visScrollRectP->left - spriteWorldP->oldVisScrollRect.left;
  273.     vScrollDelta = visScrollRectP->top - spriteWorldP->oldVisScrollRect.top;
  274.     
  275.     
  276.         // Update tiles as we scroll if tiling is turned on
  277.     if (spriteWorldP->tilingIsOn)
  278.     {
  279.             // VisScrollRect moved horizontally
  280.         if (hScrollDelta)
  281.         {
  282.                 // Get rect of new vertical section to update
  283.             tempDstRect = *visScrollRectP;
  284.             
  285.                 // Moved left
  286.             if (hScrollDelta < 0)
  287.             {
  288.                 if (tempDstRect.right > spriteWorldP->oldVisScrollRect.left)
  289.                     tempDstRect.right = spriteWorldP->oldVisScrollRect.left;
  290.             }
  291.             else    // Moved right
  292.             {
  293.                 if (tempDstRect.left < spriteWorldP->oldVisScrollRect.right)
  294.                     tempDstRect.left = spriteWorldP->oldVisScrollRect.right;
  295.             }
  296.     
  297.             (*spriteWorldP->tileRectDrawProc)(spriteWorldP, &tempDstRect, true);
  298.             SWWrapRectToWorkArea(spriteWorldP, &tempDstRect);
  299.             
  300.             
  301.                 // Did VisScrollRect moved diagonally?
  302.             if (vScrollDelta)
  303.             {
  304.                     // Get rect of new horizontal section to update
  305.                 tempDstRect = spriteWorldP->visScrollRect;
  306.                 
  307.                     // Moved up
  308.                 if (vScrollDelta < 0)
  309.                 {
  310.                     if (tempDstRect.bottom > spriteWorldP->oldVisScrollRect.top)
  311.                         tempDstRect.bottom = spriteWorldP->oldVisScrollRect.top;
  312.                 }
  313.                 else    // Moved down
  314.                 {
  315.                     if (tempDstRect.top < spriteWorldP->oldVisScrollRect.bottom)
  316.                         tempDstRect.top = spriteWorldP->oldVisScrollRect.bottom;
  317.                 }
  318.                 
  319.                     // Clip off the part we've already updated
  320.                 if (hScrollDelta < 0)
  321.                 {
  322.                     if (tempDstRect.left < spriteWorldP->oldVisScrollRect.left)
  323.                         tempDstRect.left = spriteWorldP->oldVisScrollRect.left;
  324.                 }
  325.                 else
  326.                 {
  327.                     if (tempDstRect.right > spriteWorldP->oldVisScrollRect.right)
  328.                         tempDstRect.right = spriteWorldP->oldVisScrollRect.right;
  329.                 }
  330.                 
  331.                     // We pass false here to avoid a bug which occured in the
  332.                     // tile optimizing code when updating tiles twice in one frame
  333.                 if (tempDstRect.right > tempDstRect.left)
  334.                 {
  335.                     (*spriteWorldP->tileRectDrawProc)(spriteWorldP, &tempDstRect, false);
  336.                     SWWrapRectToWorkArea(spriteWorldP, &tempDstRect);
  337.                 }
  338.             }
  339.         }        // VisScrollRect moved vertically only
  340.         else if (vScrollDelta)
  341.         {
  342.                 // Get rect of new horizontal section to update
  343.             tempDstRect = *visScrollRectP;
  344.             
  345.                 // Moved up
  346.             if (vScrollDelta < 0)
  347.             {
  348.                 if (tempDstRect.bottom > spriteWorldP->oldVisScrollRect.top)
  349.                     tempDstRect.bottom = spriteWorldP->oldVisScrollRect.top;
  350.             }
  351.             else    // Moved down
  352.             {
  353.                 if (tempDstRect.top < spriteWorldP->oldVisScrollRect.bottom)
  354.                     tempDstRect.top = spriteWorldP->oldVisScrollRect.bottom;
  355.             }
  356.  
  357.             (*spriteWorldP->tileRectDrawProc)(spriteWorldP, &tempDstRect, true);
  358.             SWWrapRectToWorkArea(spriteWorldP, &tempDstRect);
  359.         }
  360.     }
  361.     
  362.     
  363.     //-----------------erase the sprites--------------------
  364.     
  365.         // Set the port to the work area so we can draw in it
  366.     SetGWorld(spriteWorldP->workFrameP->framePort, nil);
  367.     
  368.     curSpriteLayerP = spriteWorldP->headSpriteLayerP;
  369.     curTileLayer = 0;
  370.     
  371.         // iterate through the layers in this world
  372.     while (curSpriteLayerP != NULL)
  373.     {
  374.         curSpriteP = curSpriteLayerP->headSpriteP;
  375.         
  376.         if (curSpriteLayerP->tileLayer > curTileLayer)
  377.             curTileLayer = curSpriteLayerP->tileLayer;
  378.         
  379.             // iterate through the sprites in this layer
  380.         while (curSpriteP != NULL)
  381.         {
  382.             SW_ASSERT(curSpriteP->curFrameP->isFrameLocked);
  383.             curSpriteP->tileDepth = curTileLayer;
  384.             
  385.                 // Clip the sprite's destOffscreenRect with visScrollRect.
  386.             if (curSpriteP->isVisible)
  387.             {
  388.                 curSpriteP->destOffscreenRect = curSpriteP->destFrameRect;
  389.                 curSpriteP->clippedSourceRect = curSpriteP->curFrameP->frameRect;
  390.                 
  391.  
  392.                 if (curSpriteP->destOffscreenRect.top < visScrollRectP->top)
  393.                 {
  394.                     curSpriteP->clippedSourceRect.top += visScrollRectP->top - 
  395.                             curSpriteP->destOffscreenRect.top;
  396.                     curSpriteP->destOffscreenRect.top = visScrollRectP->top;
  397.                 }
  398.                 
  399.                 if (curSpriteP->destOffscreenRect.bottom > visScrollRectP->bottom)
  400.                 {
  401.                     curSpriteP->clippedSourceRect.bottom += visScrollRectP->bottom - 
  402.                             curSpriteP->destOffscreenRect.bottom;
  403.                     curSpriteP->destOffscreenRect.bottom = visScrollRectP->bottom;
  404.                 }
  405.                 
  406.                 if (curSpriteP->destOffscreenRect.left < visScrollRectP->left)
  407.                 {
  408.                     curSpriteP->clippedSourceRect.left += visScrollRectP->left - 
  409.                             curSpriteP->destOffscreenRect.left;
  410.                     curSpriteP->destOffscreenRect.left = visScrollRectP->left;
  411.                 }
  412.                 
  413.                 if (curSpriteP->destOffscreenRect.right > visScrollRectP->right)
  414.                 {
  415.                     curSpriteP->clippedSourceRect.right += visScrollRectP->right - 
  416.                             curSpriteP->destOffscreenRect.right;
  417.                     curSpriteP->destOffscreenRect.right = visScrollRectP->right;
  418.                 }
  419.                 
  420.                 curSpriteP->destRectIsVisible =
  421.                         (curSpriteP->destOffscreenRect.right >
  422.                         curSpriteP->destOffscreenRect.left &&
  423.                         curSpriteP->destOffscreenRect.bottom >
  424.                         curSpriteP->destOffscreenRect.top);
  425.             }
  426.             
  427.             
  428.                 // Erase the sprites
  429.             if (curSpriteP->needsToBeDrawn && curSpriteP->isVisible ||
  430.                 curSpriteP->needsToBeErased && !curSpriteP->isVisible)
  431.             {
  432.                 // Recalculate the oldOffscreenRect (tempDstRect) from scratch. We can't save the 
  433.                 // destOffscreenRect from the previous frame, since an invisible Sprite that
  434.                 // is made visible many frames later could have an incorrect oldOffscreenRect,
  435.                 // meaning the Sprite would be erased even if it's not currently on the screen.
  436.                 
  437.                 tempDstRect = curSpriteP->oldFrameRect;
  438.                 
  439.                 if (tempDstRect.top < spriteWorldP->oldVisScrollRect.top)
  440.                     tempDstRect.top = spriteWorldP->oldVisScrollRect.top;
  441.                 
  442.                 if (tempDstRect.bottom > spriteWorldP->oldVisScrollRect.bottom)
  443.                     tempDstRect.bottom = spriteWorldP->oldVisScrollRect.bottom;
  444.                 
  445.                 if (tempDstRect.left < spriteWorldP->oldVisScrollRect.left)
  446.                     tempDstRect.left = spriteWorldP->oldVisScrollRect.left;
  447.                 
  448.                 if (tempDstRect.right > spriteWorldP->oldVisScrollRect.right)
  449.                     tempDstRect.right = spriteWorldP->oldVisScrollRect.right;
  450.                 
  451.                     // Was the sprite visible on the screen last frame?
  452.                 if (tempDstRect.right > tempDstRect.left &&
  453.                     tempDstRect.bottom > tempDstRect.top)
  454.                 {
  455.                         // Make the tempDstRect local to the offscreen area
  456.                     tempDstRect.top -= oldVertScrollRectOffset;
  457.                     tempDstRect.bottom -= oldVertScrollRectOffset;
  458.                     tempDstRect.left -= oldHorizScrollRectOffset;
  459.                     tempDstRect.right -= oldHorizScrollRectOffset;
  460.  
  461.  
  462.                         // Add sprite to active sprite list
  463.                     if (headActiveSpriteP == NULL)
  464.                         headActiveSpriteP = curSpriteP;
  465.                     
  466.                     if (curActiveSpriteP != NULL)
  467.                         curActiveSpriteP->nextActiveSpriteP = curSpriteP;
  468.                     
  469.                     curActiveSpriteP = curSpriteP;
  470.                     
  471.                     {
  472.                         short temp;
  473.                         
  474.                             // align left edge of tempDstRect for erasing
  475.                         tempDstRect.left &=
  476.                             (spriteWorldP->workFrameP->leftAlignFactor);
  477.                         
  478.                             // align the right edge to long word boundary
  479.                         temp = tempDstRect.right &
  480.                             spriteWorldP->workFrameP->rightAlignFactor;
  481.                         if (temp != 0)
  482.                         {
  483.                             tempDstRect.right +=
  484.                                 (spriteWorldP->workFrameP->rightAlignFactor + 1) - temp;
  485.                         }
  486.  
  487.                             // align left edge of oldFrameRect - necessary for
  488.                             // deltaFrameRect below, used by idle sprite collision
  489.                         curSpriteP->oldFrameRect.left &=
  490.                             (spriteWorldP->workFrameP->leftAlignFactor);
  491.                         
  492.                             // align the right edge to long word boundary
  493.                         temp = curSpriteP->oldFrameRect.right &
  494.                             spriteWorldP->workFrameP->rightAlignFactor;
  495.                         if (temp != 0)
  496.                         {
  497.                             curSpriteP->oldFrameRect.right +=
  498.                                 (spriteWorldP->workFrameP->rightAlignFactor + 1) - temp;
  499.                         }
  500.                     }
  501.                     
  502.                         // union last rect and current rect - this is necessary for 
  503.                         // the proper redrawing of idle sprites
  504.                     curSpriteP->deltaFrameRect.top = 
  505.                         SW_MIN(curSpriteP->oldFrameRect.top, curSpriteP->destFrameRect.top);
  506.                     curSpriteP->deltaFrameRect.left = 
  507.                         SW_MIN(curSpriteP->oldFrameRect.left, curSpriteP->destFrameRect.left);
  508.                     curSpriteP->deltaFrameRect.bottom = 
  509.                         SW_MAX(curSpriteP->oldFrameRect.bottom, curSpriteP->destFrameRect.bottom);
  510.                     curSpriteP->deltaFrameRect.right = 
  511.                         SW_MAX(curSpriteP->oldFrameRect.right, curSpriteP->destFrameRect.right);
  512.                     
  513.                     
  514.                         // Erase the sprite from the work area
  515.                     SWEraseWrappedSprite(spriteWorldP, &tempDstRect);
  516.                 }
  517.                 else if (curSpriteP->destRectIsVisible)    // Sprite will be drawn
  518.                 {
  519.                         // Add sprite to active sprite list
  520.                     if (headActiveSpriteP == NULL)
  521.                         headActiveSpriteP = curSpriteP;
  522.                     
  523.                     if (curActiveSpriteP != NULL)
  524.                             curActiveSpriteP->nextActiveSpriteP = curSpriteP;
  525.                     
  526.                     curActiveSpriteP = curSpriteP;
  527.                 }
  528.             }
  529.             else if (curSpriteP->isVisible)        // Visible, idle sprites
  530.             {
  531.                 if (curSpriteP->oldRectIsVisible)
  532.                 {
  533.                         // Is idle sprite moving outside the visScrollRect?
  534.                     if ((hScrollDelta > 0 &&
  535.                         (curIdleSpriteP->destFrameRect.left < visScrollRectP->left) &&
  536.                         (curIdleSpriteP->destFrameRect.right > spriteWorldP->oldVisScrollRect.left)) ||
  537.                         (hScrollDelta < 0 &&
  538.                         (curIdleSpriteP->destFrameRect.left < spriteWorldP->oldVisScrollRect.right) &&
  539.                         (curIdleSpriteP->destFrameRect.right > visScrollRectP->right)) )
  540.                     {
  541.                             // Erase piece of idle sprite outside of visScrollRect
  542.                         tempDstRect = curSpriteP->oldFrameRect;
  543.                         
  544.                             // Get section of sprite outside visScrollRect
  545.                         if (hScrollDelta > 0)
  546.                         {
  547.                             if (tempDstRect.right > visScrollRectP->left)
  548.                                 tempDstRect.right = visScrollRectP->left;
  549.                         }
  550.                         else
  551.                         {
  552.                             if (tempDstRect.left < visScrollRectP->right)
  553.                                 tempDstRect.left = visScrollRectP->right;
  554.                         }
  555.                         
  556.                             // Clip tempDstRect with oldVisScrollRect
  557.                         if (tempDstRect.top < spriteWorldP->oldVisScrollRect.top)
  558.                             tempDstRect.top = spriteWorldP->oldVisScrollRect.top;
  559.                         if (tempDstRect.bottom > spriteWorldP->oldVisScrollRect.bottom)
  560.                             tempDstRect.bottom = spriteWorldP->oldVisScrollRect.bottom;
  561.                         if (tempDstRect.left < spriteWorldP->oldVisScrollRect.left)
  562.                             tempDstRect.left = spriteWorldP->oldVisScrollRect.left;
  563.                         if (tempDstRect.right > spriteWorldP->oldVisScrollRect.right)
  564.                             tempDstRect.right = spriteWorldP->oldVisScrollRect.right;
  565.                         
  566.                             // Make the rect local to the offscreen area
  567.                         tempDstRect.top -= spriteWorldP->vertScrollRectOffset;
  568.                         tempDstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  569.                         tempDstRect.left -= spriteWorldP->horizScrollRectOffset;
  570.                         tempDstRect.right -= spriteWorldP->horizScrollRectOffset;
  571.                         
  572.                         SWEraseWrappedSprite(spriteWorldP, &tempDstRect);
  573.                     }
  574.                     
  575.                         // Is idle sprite moving outside the visScrollRect?
  576.                     if ((vScrollDelta > 0 &&
  577.                         (curIdleSpriteP->destFrameRect.top < visScrollRectP->top) &&
  578.                         (curIdleSpriteP->destFrameRect.bottom > spriteWorldP->oldVisScrollRect.top)) ||
  579.                         (vScrollDelta < 0 &&
  580.                         (curIdleSpriteP->destFrameRect.top < spriteWorldP->oldVisScrollRect.bottom) &&
  581.                         (curIdleSpriteP->destFrameRect.bottom > visScrollRectP->bottom)) )
  582.                     {
  583.                             // Erase piece of idle sprite outside of visScrollRect
  584.                         tempDstRect = curSpriteP->oldFrameRect;
  585.                         
  586.                             // Get section of sprite outside visScrollRect
  587.                         if (vScrollDelta > 0)
  588.                         {
  589.                             if (tempDstRect.bottom > visScrollRectP->top)
  590.                                 tempDstRect.bottom = visScrollRectP->top;
  591.                         }
  592.                         else
  593.                         {
  594.                             if (tempDstRect.top < visScrollRectP->bottom)
  595.                                 tempDstRect.top = visScrollRectP->bottom;
  596.                         }
  597.                         
  598.                             // Clip tempDstRect with oldVisScrollRect
  599.                         if (tempDstRect.top < spriteWorldP->oldVisScrollRect.top)
  600.                             tempDstRect.top = spriteWorldP->oldVisScrollRect.top;
  601.                         if (tempDstRect.bottom > spriteWorldP->oldVisScrollRect.bottom)
  602.                             tempDstRect.bottom = spriteWorldP->oldVisScrollRect.bottom;
  603.                         if (tempDstRect.left < spriteWorldP->oldVisScrollRect.left)
  604.                             tempDstRect.left = spriteWorldP->oldVisScrollRect.left;
  605.                         if (tempDstRect.right > spriteWorldP->oldVisScrollRect.right)
  606.                             tempDstRect.right = spriteWorldP->oldVisScrollRect.right;
  607.                         
  608.                             // Make the rect local to the offscreen area
  609.                         tempDstRect.top -= spriteWorldP->vertScrollRectOffset;
  610.                         tempDstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  611.                         tempDstRect.left -= spriteWorldP->horizScrollRectOffset;
  612.                         tempDstRect.right -= spriteWorldP->horizScrollRectOffset;
  613.                         
  614.                         SWEraseWrappedSprite(spriteWorldP, &tempDstRect);
  615.                     }
  616.                 }
  617.                             
  618.                 
  619.                     // Is the idle sprite visible on the screen?
  620.                 if (curSpriteP->destRectIsVisible)
  621.                 {
  622.                         // Add sprite to idle sprite list
  623.                     if (headIdleSpriteP == NULL)
  624.                         headIdleSpriteP = curSpriteP;
  625.                     
  626.                     if (curIdleSpriteP != NULL)
  627.                         curIdleSpriteP->nextIdleSpriteP = curSpriteP;
  628.                     
  629.                     curIdleSpriteP = curSpriteP;
  630.                 }
  631.             }
  632.  
  633.             curSpriteP = curSpriteP->nextSpriteP;
  634.         }
  635.  
  636.         curSpriteLayerP = curSpriteLayerP->nextSpriteLayerP;    
  637.     }
  638.     
  639.     if (curActiveSpriteP != NULL)
  640.         curActiveSpriteP->nextActiveSpriteP = NULL;
  641.     
  642.     if (curIdleSpriteP != NULL)
  643.         curIdleSpriteP->nextIdleSpriteP = NULL;
  644.     
  645.  
  646.     
  647.         // This section of code iterates through the idle sprite list, drawing the tiny
  648.         // sliver of any idle sprites that have just entered the visScrollRect.
  649.     curIdleSpriteP = headIdleSpriteP;
  650.     while (curIdleSpriteP != NULL)
  651.     {
  652.             // Draw vertical piece of idle sprite if it is coming into the visScrollRect.
  653.         if ((vScrollDelta > 0 &&
  654.             (curIdleSpriteP->destFrameRect.top < visScrollRectP->bottom) &&
  655.             (curIdleSpriteP->destFrameRect.bottom > spriteWorldP->oldVisScrollRect.bottom) ) ||
  656.             (vScrollDelta < 0 &&
  657.             (curIdleSpriteP->destFrameRect.top < spriteWorldP->oldVisScrollRect.top) &&
  658.             (curIdleSpriteP->destFrameRect.bottom > visScrollRectP->top)) )
  659.         {
  660.             tempDstRect = curIdleSpriteP->destOffscreenRect;
  661.             tempSrcRect = curIdleSpriteP->clippedSourceRect;
  662.             
  663.                 // Determine whether scrolling up or down, then get 
  664.                 // section of sprite outside oldVisScrollRect.
  665.             if (vScrollDelta < 0)
  666.             {
  667.                     // Scrolling up, so get section above oldVisScrollRect
  668.                 if (tempDstRect.bottom > spriteWorldP->oldVisScrollRect.top)
  669.                 {
  670.                     tempSrcRect.bottom += spriteWorldP->oldVisScrollRect.top - 
  671.                         tempDstRect.bottom;
  672.                     tempDstRect.bottom = spriteWorldP->oldVisScrollRect.top;
  673.                 }
  674.             }
  675.             else
  676.             {
  677.                     // Scrolling down, so get section below oldVisScrollRect
  678.                 if (tempDstRect.top < spriteWorldP->oldVisScrollRect.bottom)
  679.                 {
  680.                     tempSrcRect.top += spriteWorldP->oldVisScrollRect.bottom - 
  681.                         tempDstRect.top;
  682.                     tempDstRect.top = spriteWorldP->oldVisScrollRect.bottom;
  683.                 }
  684.             }
  685.             
  686.                 // Make the sprite's rect local to the offscreen area
  687.             tempDstRect.top -= spriteWorldP->vertScrollRectOffset;
  688.             tempDstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  689.             tempDstRect.left -= spriteWorldP->horizScrollRectOffset;
  690.             tempDstRect.right -= spriteWorldP->horizScrollRectOffset;
  691.  
  692.                 // Draw the sprite in the work area
  693.             SWDrawWrappedSprite(curIdleSpriteP, spriteWorldP->workFrameP,
  694.                     &tempSrcRect, &tempDstRect);
  695.             
  696.                 // Draw tiles above sprite
  697.             if (spriteWorldP->tilingIsOn &&
  698.                 curIdleSpriteP->tileDepth <= spriteWorldP->lastActiveTileLayer)
  699.             {
  700.                 tempDstRect.top += spriteWorldP->vertScrollRectOffset;
  701.                 tempDstRect.bottom += spriteWorldP->vertScrollRectOffset;
  702.                 tempDstRect.left += spriteWorldP->horizScrollRectOffset;
  703.                 tempDstRect.right += spriteWorldP->horizScrollRectOffset;
  704.                 SWDrawTilesAboveSprite(spriteWorldP, &tempDstRect, curIdleSpriteP->tileDepth);
  705.             }
  706.         }
  707.         
  708.         
  709.             // Draw horizontal piece of idle sprite if it is coming into the visScrollRect.
  710.         if ((hScrollDelta > 0 &&
  711.             (curIdleSpriteP->destFrameRect.left < visScrollRectP->right) &&
  712.             (curIdleSpriteP->destFrameRect.right > spriteWorldP->oldVisScrollRect.right) ) ||
  713.             (hScrollDelta < 0 &&
  714.             (curIdleSpriteP->destFrameRect.left < spriteWorldP->oldVisScrollRect.left) &&
  715.             (curIdleSpriteP->destFrameRect.right > visScrollRectP->left)) )
  716.         {
  717.             tempDstRect = curIdleSpriteP->destOffscreenRect;
  718.             tempSrcRect = curIdleSpriteP->clippedSourceRect;
  719.             
  720.                 // Determine whether scrolling left or right, then get 
  721.                 // section of sprite outside oldVisScrollRect.
  722.             if (hScrollDelta < 0)
  723.             {
  724.                     // Scrolling left, so get section to the left of oldVisScrollRect
  725.                 if (tempDstRect.right > spriteWorldP->oldVisScrollRect.left)
  726.                 {
  727.                     tempSrcRect.right += spriteWorldP->oldVisScrollRect.left - 
  728.                         tempDstRect.right;
  729.                     tempDstRect.right = spriteWorldP->oldVisScrollRect.left;
  730.                 }
  731.             }
  732.             else
  733.             {
  734.                     // Scrolling right, so get section to the right of oldVisScrollRect
  735.                 if (tempDstRect.left < spriteWorldP->oldVisScrollRect.right)
  736.                 {
  737.                     tempSrcRect.left += spriteWorldP->oldVisScrollRect.right - 
  738.                         tempDstRect.left;
  739.                     tempDstRect.left = spriteWorldP->oldVisScrollRect.right;
  740.                 }
  741.             }
  742.             
  743.             
  744.                 // Make the sprite's rect local to the offscreen area
  745.             tempDstRect.top -= spriteWorldP->vertScrollRectOffset;
  746.             tempDstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  747.             tempDstRect.left -= spriteWorldP->horizScrollRectOffset;
  748.             tempDstRect.right -= spriteWorldP->horizScrollRectOffset;
  749.  
  750.                 // Draw the sprite in the work area
  751.             SWDrawWrappedSprite(curIdleSpriteP, spriteWorldP->workFrameP,
  752.                     &tempSrcRect, &tempDstRect);
  753.             
  754.                 // Draw tiles above sprite
  755.             if (spriteWorldP->tilingIsOn &&
  756.                 curIdleSpriteP->tileDepth <= spriteWorldP->lastActiveTileLayer)
  757.             {
  758.                 tempDstRect.top += spriteWorldP->vertScrollRectOffset;
  759.                 tempDstRect.bottom += spriteWorldP->vertScrollRectOffset;
  760.                 tempDstRect.left += spriteWorldP->horizScrollRectOffset;
  761.                 tempDstRect.right += spriteWorldP->horizScrollRectOffset;
  762.                 SWDrawTilesAboveSprite(spriteWorldP, &tempDstRect, curIdleSpriteP->tileDepth);
  763.             }
  764.         }
  765.     
  766.         curIdleSpriteP = curIdleSpriteP->nextIdleSpriteP;
  767.     }
  768.     
  769.  
  770.         // update flagged background rects
  771.     curRectStructP = spriteWorldP->headUpdateRectP;
  772.     while ( curRectStructP != NULL )
  773.     {
  774.         tempDstRect = curRectStructP->updateRect;
  775.         
  776.             // Make the rect local to the offscreen area
  777.         tempDstRect.top -= spriteWorldP->vertScrollRectOffset;
  778.         tempDstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  779.         tempDstRect.left -= spriteWorldP->horizScrollRectOffset;
  780.         tempDstRect.right -= spriteWorldP->horizScrollRectOffset;
  781.         
  782.             // We're not really erasing a sprite, just copying while wrapping
  783.         SWEraseWrappedSprite(spriteWorldP, &tempDstRect);
  784.         curRectStructP = curRectStructP->nextRectStructP;
  785.     }
  786.     
  787.         // Redraw idle sprites that were erased by a tile
  788.     if (spriteWorldP->numTilesChanged > 0)
  789.         SWCheckWrappedIdleSpritesWithTiles(spriteWorldP, headIdleSpriteP);
  790.  
  791.         // Redraw idle sprites that were erased by an updateRect
  792.     if (spriteWorldP->headUpdateRectP != NULL)
  793.         SWCheckWrappedIdleSpritesWithRects(spriteWorldP, headIdleSpriteP);
  794.     
  795.         // Call the postEraseCallBack
  796.     if (spriteWorldP->postEraseCallBack != NULL)
  797.         (*spriteWorldP->postEraseCallBack)(spriteWorldP);
  798.  
  799.  
  800.     //-----------------draw the sprites-------------------
  801.  
  802.     curSpriteLayerP = spriteWorldP->headSpriteLayerP;
  803.  
  804.         // iterate through the layers in this world
  805.     while (curSpriteLayerP != NULL)
  806.     {
  807.         curSpriteP = curSpriteLayerP->headSpriteP;
  808.  
  809.             // iterate through the sprites in this layer
  810.         while (curSpriteP != NULL)
  811.         {
  812.             if (curSpriteP->isVisible)
  813.             {
  814.                     // Make the sprite's rect local to the offscreen area
  815.                 curSpriteP->destOffscreenRect.top -= spriteWorldP->vertScrollRectOffset;
  816.                 curSpriteP->destOffscreenRect.bottom -= spriteWorldP->vertScrollRectOffset;
  817.                 curSpriteP->destOffscreenRect.left -= spriteWorldP->horizScrollRectOffset;
  818.                 curSpriteP->destOffscreenRect.right -= spriteWorldP->horizScrollRectOffset;
  819.                 
  820.                 if (curSpriteP->needsToBeDrawn)
  821.                 {
  822.                         // Is the sprite visible on the screen?
  823.                     if (curSpriteP->destRectIsVisible)
  824.                     {
  825.                         gSWCurrentSpriteBeingDrawn = curSpriteP;
  826.                         
  827.                             // Draw the sprite in the work area
  828.                         SWDrawWrappedSprite(curSpriteP, spriteWorldP->workFrameP,
  829.                             &curSpriteP->clippedSourceRect, 
  830.                             &curSpriteP->destOffscreenRect);
  831.                         
  832.                         gSWCurrentSpriteBeingDrawn = NULL;
  833.                         
  834.                             // Draw tiles above sprite
  835.                         if (spriteWorldP->tilingIsOn &&
  836.                             curSpriteP->tileDepth <= spriteWorldP->lastActiveTileLayer)
  837.                         {
  838.                             tempDstRect = curSpriteP->destOffscreenRect;
  839.                             tempDstRect.top += spriteWorldP->vertScrollRectOffset;
  840.                             tempDstRect.bottom += spriteWorldP->vertScrollRectOffset;
  841.                             tempDstRect.left += spriteWorldP->horizScrollRectOffset;
  842.                             tempDstRect.right += spriteWorldP->horizScrollRectOffset;
  843.                             SWDrawTilesAboveSprite(spriteWorldP, &tempDstRect, curSpriteP->tileDepth);
  844.                         }
  845.                     }
  846.                 }
  847.                 else
  848.                 {
  849.                         // Is the idle sprite visible on the screen?
  850.                     if (curSpriteP->destRectIsVisible)
  851.                     {
  852.                         SWCheckWrappedIdleSpriteOverlap(spriteWorldP, 
  853.                             curSpriteP, headActiveSpriteP);
  854.                     }
  855.                 }
  856.             }
  857.             
  858.             
  859.             ///
  860.             //  This is where a lot of code was removed.
  861.             //  (most of it moved to SWFinishMultiScreenAnimation)
  862.             ///
  863.             
  864.  
  865.             curSpriteP = curSpriteP->nextSpriteP;
  866.         }
  867.         
  868.         curSpriteLayerP = curSpriteLayerP->nextSpriteLayerP;
  869.     }
  870.     
  871.     spriteWorldP->oldVisScrollRect = spriteWorldP->visScrollRect;
  872.     
  873.     
  874.         // Call the postDrawCallBack
  875.     if (spriteWorldP->postDrawCallBack != NULL)
  876.         (*spriteWorldP->postDrawCallBack)(spriteWorldP);
  877.     
  878.     
  879.     //-----------------update the screen--------------------
  880.     
  881.         // Set the port to the window
  882.     SetGWorld(spriteWorldP->windowFrameP->framePort, nil);
  883.     
  884.     if (spriteWorldP->usingVBL)
  885.     {  
  886.         spriteWorldP->vblTaskRec.hasVBLFired = false;
  887.         while ( !spriteWorldP->vblTaskRec.hasVBLFired )
  888.         {}
  889.     }
  890.     
  891.         // Copy offscreen area to screen while wrapping
  892.     SWWrapWorkAreaToFrame(spriteWorldP, spriteWorldP->windowFrameP, &spriteWorldP->windRect);
  893.     
  894.     
  895.             // dispose of flagged background rects
  896.     nextRectStructP = spriteWorldP->headUpdateRectP;
  897.     while ( nextRectStructP != NULL )
  898.     {
  899.         curRectStructP = nextRectStructP;
  900.         nextRectStructP = curRectStructP->nextRectStructP;
  901.         DisposePtr( (Ptr)curRectStructP );
  902.     }
  903.     spriteWorldP->headUpdateRectP = NULL;
  904.     
  905.     spriteWorldP->numTilesChanged = 0;
  906.     
  907.     
  908.         // Remove the deadSpriteLayer if we added it earlier.
  909.     if ( spriteWorldP->deadSpriteLayerP->headSpriteP != NULL )
  910.     {
  911.         SWRemoveSpriteLayer(spriteWorldP, spriteWorldP->deadSpriteLayerP);
  912.     }
  913.     
  914.     gSWCurrentSpriteWorld = NULL;
  915. }
  916.  
  917.  
  918. ///--------------------------------------------------------------------------------------
  919. //    SWFinishMultiScreenAnimation
  920. ///--------------------------------------------------------------------------------------
  921.  
  922. SW_FUNC void SWFinishMultiScreenAnimation(
  923.     SpriteWorldPtr spriteWorldP)
  924. {
  925.     register SpriteLayerPtr     curSpriteLayerP;
  926.     register SpritePtr             curSpriteP;
  927.     
  928.     
  929.     curSpriteLayerP = spriteWorldP->headSpriteLayerP;
  930.  
  931.         // iterate through the layers in this world
  932.     while (curSpriteLayerP != NULL)
  933.     {
  934.         curSpriteP = curSpriteLayerP->headSpriteP;
  935.  
  936.             // iterate through the sprites in this layer
  937.         while (curSpriteP != NULL)
  938.         {
  939.                 // Set last rect to current rect
  940.             curSpriteP->oldFrameRect = curSpriteP->destFrameRect;
  941.             
  942.             curSpriteP->needsToBeDrawn = false;
  943.             curSpriteP->needsToBeErased = false;
  944.  
  945.             curSpriteP = curSpriteP->nextSpriteP;
  946.         }
  947.         
  948.         curSpriteLayerP = curSpriteLayerP->nextSpriteLayerP;
  949.     }
  950. }
  951.  
  952.